package com.aco.fatureapp.utilitary;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import android.content.Context;
import android.os.Environment;
import android.widget.Toast;

import com.orm.SugarDb;

public class FileUtils {

	/*
	 * Diretório Padrão
	 */
	public static String DIRETORIO_PADRAO = "ifature/";

	/*
	 * Módulos
	 */
	public static String DIRETORIO_IMAGENS = "imagens";

	public static String DIRETORIO_DB_BACKUPS = "db_backups";

	public static String DIRETORIO_IMG_BACKUPS = "img_backups";

	/**
	 * Verifica se o cartão de memória está disponível para uso.
	 *
	 * @return
	 */
	public static boolean isSDCardAvailable() {
		boolean mExternalStorageAvailable = true;
		boolean mExternalStorageWriteable = false;
		final String state = Environment.getExternalStorageState();

		if (Environment.MEDIA_MOUNTED.equals(state)) {
			mExternalStorageWriteable = true;
		}
		else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
			mExternalStorageWriteable = false;
		}
		else {
			mExternalStorageAvailable = mExternalStorageWriteable = false;
		}

		return mExternalStorageAvailable && mExternalStorageWriteable;
	}

	/**
	 * Retorna os arquivos de um diretório.
	 *
	 * @param dir
	 */
	public static File[] getListFiles(final String dir) {
		final String storagePath = getStorageDirectory().getAbsolutePath();

		final File file = new File(storagePath, dir);

		if (file.exists()) {
			return file.isDirectory() ? file.listFiles() : new File[] { file };
		}

		return null;
	}

	/**
	 * Responsável por criar diretórios, caso não existam.
	 *
	 * @return
	 */
	public static File createIfNotExist(final String dir) {
		final File storageDir = getStorageDirectory();
		final File file = new File(storageDir + "/" + dir);

		if (!file.exists()) {
			final boolean success = file.mkdirs();

			if (success) {
				return new File(storageDir + "/" + dir);
			}
		}

		return file;
	}

	/**
	 *
	 * Esse método é responsável por verificar toda a árvore de diretórios, e
	 * caso ainda não exista, criá-la a partir do diretório padrão.
	 *
	 * DIRETORIO_PADRAO / DIRETORIO_[MODULO]
	 *
	 * @param dir
	 */
	public static void checkDirectoryTree(final String... children) {
		for (int i = 0; i < children.length; i++) {
			createIfNotExist(DIRETORIO_PADRAO + children[i]);
		}
	}

	/**
	 * Mover um arquivo para um diretório de destino.
	 *
	 * @param file
	 * @param destinationDir
	 */
	public static void move(final File file, final String destinationDir) {
		final String SDCardPath = Environment.getExternalStorageDirectory()
				.getAbsolutePath();

		final File directoryOut = new File(SDCardPath + destinationDir);

		if (!directoryOut.exists()) {
			directoryOut.mkdir();
		}

		file.renameTo(new File(SDCardPath, destinationDir + "/"
				+ file.getName()));
	}

	/**
	 * Responsável por converter um arquivo em um array de bytes.
	 *
	 * @param file
	 * @return
	 * @throws IOException
	 */
	public static byte[] toByteArray(final File file) throws IOException {
		final FileInputStream in = new FileInputStream(file);

		final ByteArrayOutputStream baos = new ByteArrayOutputStream();

		int x = 0;
		while ((x = in.read()) != -1) {
			baos.write(x);
		}

		in.close();

		return baos.toByteArray();
	}

	/**
	 *
	 * Busca pelo diretório raiz de armazenamento, sendo o SDCard a primeira
	 * opção de retorno.
	 *
	 * @return File
	 */
	public static File getStorageDirectory() {
		if (isSDCardAvailable()) {
			return Environment.getExternalStorageDirectory();
		}

		return Environment.getRootDirectory();
	}

	/**
	 *
	 * Responsável por executar a lógica de backup do banco de dados em um
	 * arquivo de localização pré-definida.
	 *
	 * [ifature/db_backups/ifature-mobile.db]
	 *
	 * @param context
	 * @throws IOException
	 */
	public static void backup(final Context context, String fileName)
			throws IOException {

		final SugarDb helper = new SugarDb(context);

		if (fileName == null) {
			fileName = helper.getDatabaseName();
		}

		final String dataBaseName = context.getApplicationInfo().dataDir
				+ "/databases/" + helper.getDatabaseName();

		final String storagePath = getStorageDirectory().getAbsolutePath();

		final String backupFileName = storagePath + "/" + DIRETORIO_PADRAO
				+ DIRETORIO_DB_BACKUPS + "/" + fileName;

		helper.close();

		final InputStream mInput = new FileInputStream(dataBaseName);

		final OutputStream mOutput = new FileOutputStream(backupFileName);

		int length;
		final byte[] buffer = new byte[1024];

		while ((length = mInput.read(buffer)) > 0) {
			mOutput.write(buffer, 0, length);
		}

		mOutput.flush();
		mOutput.close();
		mInput.close();

	}

	/**
	 *
	 * Responsável por buscar um arquivo de backup no diretório
	 * [ifature/db_backups] e restaurar suas informações na base de dados do
	 * app.
	 *
	 * @param context
	 */
	public static void restore(final Context context) {
		try {
			final SugarDb helper = new SugarDb(context);

			final String dataBaseName = context.getApplicationInfo().dataDir
					+ "/databases/" + helper.getDatabaseName();

			final String storagePath = getStorageDirectory().getAbsolutePath();

			final String backupFileName = storagePath + "/" + DIRETORIO_PADRAO
					+ DIRETORIO_DB_BACKUPS + "/" + helper.getDatabaseName();

			final File file = new File(backupFileName);

			OutputStream myOutput = new FileOutputStream(dataBaseName);

			if (file.exists()) {

				final InputStream myInputs = new FileInputStream(file);

				int length;
				final byte[] buffer = new byte[1024];

				while ((length = myInputs.read(buffer)) > 0) {
					myOutput.write(buffer, 0, length);
				}

				myOutput.flush();

				myOutput.close();

				myInputs.close();

				Toast.makeText(context, "Restore realizado com sucesso!",
						Toast.LENGTH_SHORT).show();
			}
			else {
				Toast.makeText(context, "Arquivo de restore não encontrado.",
						Toast.LENGTH_SHORT).show();

				myOutput.close();
			}

			myOutput.close();
		}
		catch (final FileNotFoundException e) {
			Toast.makeText(context, "Arquivo de restore não encontrado.",
					Toast.LENGTH_SHORT).show();
		}
		catch (final Exception e) {
			Toast.makeText(context,
					"Falha no processo de restore da base de dados.",
					Toast.LENGTH_SHORT).show();
		}
	}
}